package com.naiterui.ehp.bp.support.config;

import static org.springframework.http.MediaType.*;

import java.util.List;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.naiterui.ehp.bp.support.mvc.HeaderDecodeArgResolverHandler;
import com.naiterui.ehp.bp.support.mvc.RequestObjectArgResolverHandler;
import com.naiterui.ehp.bp.support.security.InterceptorAddition;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.support.utils.web.DateBindingInitializer;

/**
 * <pre>
 *      继承WebMvcConfigurer，通过方法入口进行spring mvc注入
 *      业务服继承改类注入所需Interceptor、converter等
 *      必须配合{@EnableWebMvc，@Configuration}注解使用
 *      这里使用了@ConditionalOnMissingBean，如果其他项目想要覆盖默认配置，那么需要在使用@Configuration("webConfig")
 * </pre>
 *
 * @author mudou
 * @since 1.0.0
 */
@Configuration
public class WebMvcAutoConfiguration extends WebMvcConfigurationSupport {

    @Autowired(required = false)
    private List<InterceptorAddition> interceptorAdditions = Lists.newArrayList();

    /**
     * 创建json转换器
     *
     * @return jackson转换器
     *
     * @date 2017年08月30日
     * @since 1.0.0
     */
    public static MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(JsonMapper.getJsonMapper());
        converter.setSupportedMediaTypes(Lists.newArrayList(APPLICATION_JSON, TEXT_HTML, TEXT_PLAIN));
        converter.setDefaultCharset(Charsets.UTF_8);
        return converter;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/favicon.ico").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/schedule/static/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    @Override
    public final void addInterceptors(InterceptorRegistry registry) {

        /**
         * 业务服务拦截器
         */
        this.interceptorAdditions.forEach(addition -> {
            InterceptorRegistration registration = registry.addInterceptor(addition.getInterceptor());
            if (ArrayUtils.isNotEmpty(addition.getAddPathPatterns())) {
                registration.addPathPatterns(addition.getAddPathPatterns());
            }
            if (ArrayUtils.isNotEmpty(addition.getExcludePathPatterns())) {
                registration.excludePathPatterns(addition.getExcludePathPatterns());
            }
            if (null != addition.getPathMatcher()) {
                registration.pathMatcher(addition.getPathMatcher());
            }
        });
    }

    // ==================================================

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        //如果设置true "/user" 就会匹配 "/user.*",也就是说,"/user.html" 的请求会被 "/user" 的 Controller所拦截.
        configurer.setUseSuffixPatternMatch(false);
    }

    @Override
    public final void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).favorParameter(true).defaultContentType(APPLICATION_JSON_UTF8);
    }

    @Override
    public final void configureAsyncSupport(AsyncSupportConfigurer configurer) {

    }

    @Override
    public final void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

    }

    @Override
    public final void addFormatters(FormatterRegistry registry) {

    }

    @Override
    public final void addCorsMappings(CorsRegistry registry) {
        // registry.addMapping("/**").allowedOriginPatterns("*").allowedMethods("*").allowedHeaders("*")
        // .allowCredentials(true).maxAge(3600);
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {}

    @Override
    public final void configureViewResolvers(ViewResolverRegistry registry) {}

    @Override
    public final void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers
            .add(new RequestObjectArgResolverHandler(WebMvcAutoConfiguration.mappingJacksonHttpMessageConverter()));
        argumentResolvers.add(new HeaderDecodeArgResolverHandler());
    }

    @Override
    public final void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {}

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 将StringHttpMessageConverter的默认编码设为UTF-8
        converters.add(new StringHttpMessageConverter(Charsets.UTF_8));
        converters.add(WebMvcAutoConfiguration.mappingJacksonHttpMessageConverter());
    }

    @Override
    protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
        RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter();
        requestMappingHandlerAdapter.setWebBindingInitializer(new DateBindingInitializer());
        return requestMappingHandlerAdapter;
    }


}
